define(['vue', 'components/CMessage'],function () {
  const defaults = {
    title: undefined,
    message: '',
    type: '',
    showInput: false,
    showClose: true,
    modalFade: true,
    lockScroll: true,
    closeOnClickModal: true,
    closeOnPressEscape: true,
    inputValue: null,
    inputPlaceholder: '',
    inputPattern: null,
    inputValidator: null,
    inputErrorMessage: '',
    showConfirmButton: true,
    showCancelButton: false,
    confirmButtonPosition: 'right',
    confirmButtonHighlight: false,
    cancelButtonHighlight: false,
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    confirmButtonClass: '',
    cancelButtonClass: '',
    customClass: '',
    beforeClose: null
  }

  const Vue = require('vue')
  const CMessage = require('components/CMessage')

  const MessageBoxConstructor = Vue.extend(CMessage)

  const hasOwnProperty = Object.prototype.hasOwnProperty

  function hasOwn (obj, key) {
    return hasOwnProperty.call(obj, key)
  }

  function isVNode (node) {
    return typeof node === 'object' && hasOwn(node, 'componentOptions')
  }

  function merge (target) {
    for (let i = 1, j = arguments.length; i < j; i++) {
      let source = arguments[i] || {}
      for (let prop in source) {
        if (source.hasOwnProperty(prop)) {
          let value = source[prop]
          if (value !== undefined) {
            target[prop] = value
          }
        }
      }
    }

    return target
  }

  let currentMsg, instance
  let msgQueue = []

  const defaultCallback = action => {
    if (currentMsg) {
      let callback = currentMsg.callback
      if (typeof callback === 'function') {
        if (instance.showInput) {
          callback(instance.inputValue, action)
        } else {
          callback(action)
        }
      }
      if (currentMsg.resolve) {
        if (action === 'confirm') {
          if (instance.showInput) {
            currentMsg.resolve({value: instance.inputValue, action})
          } else {
            currentMsg.resolve(action)
          }
        } else if (action === 'cancel' && currentMsg.reject) {
          currentMsg.reject(action)
        }
      }
    }
  }

  const initInstance = () => {
    instance = new MessageBoxConstructor({
      el: document.createElement('div')
    })

    instance.callback = defaultCallback
  }

  const showNextMsg = () => {
    if (!instance) {
      initInstance()
    }
    instance.action = ''

    if (!instance.visible || instance.closeTimer) {
      if (msgQueue.length > 0) {
        currentMsg = msgQueue.shift()

        let options = currentMsg.options
        for (let prop in options) {
          if (options.hasOwnProperty(prop)) {
            instance[prop] = options[prop]
          }
        }
        if (options.callback === undefined) {
          instance.callback = defaultCallback
        }

        let oldCb = instance.callback
        instance.callback = (action, instance) => {
          oldCb(action, instance)
          showNextMsg()
        }
        if (isVNode(instance.message)) {
          instance.$slots.default = [instance.message]
          instance.message = null
        } else {
          delete instance.$slots.default
        }
        ['modal', 'showClose', 'closeOnClickModal', 'closeOnPressEscape'].forEach(prop => {
          if (instance[prop] === undefined) {
            instance[prop] = true
          }
        })
        document.body.appendChild(instance.$el)

        Vue.nextTick(() => {
          instance.visible = true
        })
      }
    }
  }

  const MessageBox = function (options, callback) {
    if (Vue.prototype.$isServer) return
    if (typeof options === 'string') {
      options = {
        message: options
      }
      if (arguments[1]) {
        options.title = arguments[1]
      }
      if (arguments[2]) {
        options.type = arguments[2]
      }
    } else if (options.callback && !callback) {
      callback = options.callback
    }

    if (typeof Promise !== 'undefined') {
      return new Promise((resolve, reject) => { // eslint-disable-line
        msgQueue.push({
          options: merge({}, defaults, MessageBox.defaults, options),
          callback: callback,
          resolve: resolve,
          reject: reject
        })

        showNextMsg()
      })
    } else {
      msgQueue.push({
        options: merge({}, defaults, MessageBox.defaults, options),
        callback: callback
      })

      showNextMsg()
    }
  }

  MessageBox.setDefaults = defaults => {
    MessageBox.defaults = defaults
  }

  MessageBox.alert = (message, title, options) => {
    if (typeof title === 'object') {
      options = title
      title = ''
    } else if (title === undefined) {
      title = ''
    }
    return MessageBox(merge({
      title: title,
      message: message,
      $type: 'alert',
      closeOnPressEscape: false,
      closeOnClickModal: false
    }, options))
  }

  MessageBox.confirm = (message, title, options) => {
    if (typeof title === 'object') {
      options = title
      title = ''
    } else if (title === undefined) {
      title = ''
    }
    return MessageBox(merge({
      title: title,
      message: message,
      $type: 'confirm',
      showCancelButton: true
    }, options))
  }

  MessageBox.prompt = (message, title, options) => {
    if (typeof title === 'object') {
      options = title
      title = ''
    } else if (title === undefined) {
      title = ''
    }
    return MessageBox(merge({
      title: title,
      message: message,
      showCancelButton: true,
      showInput: true,
      $type: 'prompt'
    }, options))
  }

  MessageBox.close = () => {
    instance.visible = false
    msgQueue = []
    currentMsg = null
  }

  function install (Clazz) {
    Clazz.prototype.$msgbox = MessageBox
    Clazz.prototype.$alert = MessageBox.alert
    Clazz.prototype.$confirm = MessageBox.confirm
    Clazz.prototype.$prompt = MessageBox.prompt
  }


  return {
    install
  }
})
